package com.kly.sc.api.application.controller.order;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.nacos.api.config.annotation.NacosValue;
import com.fqgj.base.services.redis.RedisClient;
import com.fqgj.common.api.Response;
import com.fqgj.common.api.annotations.ParamsValidate;
import com.google.common.collect.Maps;
import com.kly.dto.*;
import com.kly.enums.*;
import com.kly.req.ReceiveNotifyRequest;
import com.kly.req.RepayRequest;
import com.kly.req.RepayStatusRequest;
import com.kly.rsp.RepayResponse;
import com.kly.rsp.RepayStatusResponse;
import com.kly.sc.api.application.annos.SignIgnore;
import com.kly.sc.api.application.annos.VisitorAccessible;
import com.kly.sc.api.application.constant.ApiRedisKeys;
import com.kly.sc.api.application.consts.Constants;
import com.kly.sc.api.application.controller.order.request.*;
import com.kly.sc.api.application.controller.order.rsp.ApplePaySuccessResp;
import com.kly.sc.api.application.controller.order.rsp.GenerateOrderResp;
import com.kly.sc.api.application.helper.RequestLocalInfo;
import com.kly.sc.api.application.service.utils.BaseComponent;
import com.kly.sc.api.application.utils.Result;
import com.kly.sc.api.application.utils.RpcUtils;
import com.kly.sc.api.infras.app.RequestBasicInfo;
import com.kly.sc.api.infras.utils.StringUtils;
import com.kly.service.*;
import com.kly.service.pay.ApplePayService;
import com.kly.service.pay.RepayService;
import com.kly.user.dto.UserPromotionRecordDto;
import com.kly.user.enums.AdjustEventDefType;
import com.kly.user.enums.AppCodeEnum;
import com.kly.user.enums.AppsFlyerEventDefType;
import com.kly.user.service.AdjustService;
import com.kly.user.service.AppsflyerService;
import com.kly.user.service.UserMsgService;
import com.kly.user.service.UserPromotionRecordService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.*;
import java.util.stream.Collectors;

import static com.kly.enums.ProductCategory.*;

@RestController
@RequestMapping("api/order")
@Api(value = "/api/order", tags = "订单")
public class OrderController extends BaseComponent {

    private final Logger logger = LoggerFactory.getLogger(getClass());

    @Resource
    TOrderService tOrderService;
    @Resource
    MemberService memberService;
    @Resource
    MemberBenefitsService memberBenefitsService;
    @Resource
    UserVasPurchasesService userVasPurchasesService;
    @Resource
    RedisClient redisClient;
    @Resource
    AppsflyerService appsflyerService;
    @Resource
    RepayService repayService;
    @NacosValue(value = "${api.payment.callback.url}", autoRefreshed = true)
    private String paymentCallbackUrl;
    @NacosValue(value = "${api.payment.subscriptions.mock}", autoRefreshed = true)
    private Boolean generateUserBenefitBeforePaymentCheckFlag;
    @NacosValue(value = "${api.payment.user.mock}", autoRefreshed = true)
    private String apiPaymentUserMock;
    @Resource
    AdjustService adjustService;
    @Resource
    UserMsgService userMsgService;

    @Resource
    private UserPromotionRecordService userPromotionRecordService;
    @Resource
    private ProductService productService;
    @Resource
    private ApplePayService applePayService;

    /**
     * 添加支付快照开关
     */
    @NacosValue(value = "${order.snapshot.add.switch:true}", autoRefreshed = true)
    private Boolean orderSnapshotAddSwitch;
    /**
     * 显示支付错误开关
     */
    @NacosValue(value = "${order.pay.failed.switch:true}", autoRefreshed = true)
    private Boolean orderPayFailedSwitch;
    /**
     * 支付超时时间
     */
    @NacosValue(value = "${order.pay.timeout:7200}", autoRefreshed = true)
    private Integer orderPayTimeOut;


    public static final String PAY_REQUEST_TOKEN = "pay_request_{}";
    /**
     * af上报金额闽值
     */
    @NacosValue(value = "${amount.threshold.value:0.2}", autoRefreshed = true)
    private String amountThresholdValue;
    /**
     * 商品类型: 1-消耗类 2-订阅类
     */
    public static final Integer purchaseProductType = 1;
    public static final Integer purchaseProductTypeSubscriptions = 2;


    /**
     * 添加支付订单操作明细
     */
    @ResponseBody
    @RequestMapping(value = "/log", method = RequestMethod.POST)
    @ParamsValidate
    public Response addOrderEvent(@RequestBody() OrderEventRequest request) {
        try {
            final String appVersion = RequestLocalInfo.getRequestBasicInfo().getAppVersionName();
            final OrderDetailReq orderDetailReq = OrderDetailReq.builder().appCode(getAppCode()).appVersion(appVersion).eventId(request.getEventId()).userCode(request.getUserCode())
                    .productCode(request.getProductCode()).orderNo(request.getOrderNo()).orderId(request.getOrderId()).eventCode(request.getEventCode())
                    .eventName(request.getEventName()).content(request.getSnapshotContent()).build();
            tOrderService.addOrderEventLog(orderDetailReq);
            return Response.ok();
        } catch (Exception e) {
            logger.error("===addOrderEventFailed, request:{}", JSONObject.toJSONString(request), e);
        }
        return Response.ok();

    }

    /**
     * 初始化订单
     *
     * @param createOrderReq 购买产品信息
     * @return 订单结果
     */
    @RequestMapping("/generateOrder")
    public Response generateOrder(@Valid @RequestBody CreateOrderReq createOrderReq) {
        ProductDto productDto = getProductDto(createOrderReq.getProductCode());
        final String userCode = RequestLocalInfo.getCurrentUser().getUserCode();

        if (Objects.isNull(productDto)) {
            logger.error("The product not exists, userCode:{}, params:{}", userCode, JSONObject.toJSONString(createOrderReq));
            return Response.error("The product not exists");
        }

        // 生成订单
        final TOrderDto order = addOrder(createOrderReq, productDto, userCode);

        return Response.ok(GenerateOrderResp.toVo(order, productDto, purchaseProductTypeSubscriptions, amountThresholdValue,orderPayFailedSwitch, orderPayTimeOut));
    }

    @PostMapping("/apple/pay/success")
    @ApiOperation(value = "/apple/pay/success", notes = "苹果支付成功")
    public Result<ApplePaySuccessResp> applePaySuccess(@Valid @RequestBody ApplePaySuccessReq req) {
        final String userCode = RequestLocalInfo.getCurrentUser().getUserCode();
        String appCode = RequestLocalInfo.getRequestBasicInfo().getAppCode();
        String reqJson = JSONObject.toJSONString(req);
        logger.info("[applePaySuccess] userCode:{}, orderNo:{}, requestStr:{}", userCode, req.getOrderNo(), reqJson);

        if (StringUtils.isEmpty(req.getPayReceipt())) {
            logger.error("[applePaySuccess] The purchaseToken should not empty, userCode:{}, orderNo:{} params:{}", userCode, req.getOrderNo(), reqJson);
            return Result.fail();
        }

        ApplePayDto applePayDTO = new ApplePayDto();
        applePayDTO.setUserCode(userCode);
        applePayDTO.setTransactionReceipt(req.getPayReceipt());
        Integer notifyOfApplePayResp = applePayService.notifyOfApplePay(applePayDTO);
        if (notifyOfApplePayResp != 1) {
            return Result.fail();
        }

        final TOrderDto order = RpcUtils.getResult(tOrderService.queryOrderByOrderNo(req.getOrderNo()));
        final Response<TOrderDto> response = createUserBenefits(getProductDto(order.getProductCode()), userCode, order.getOrderNo());
        // 更新ios订单号
        if (response.isSuccess() && response.getData() != null) {
            final TOrderDto orderDto = response.getData();
            orderDto.setOrderId(req.getOrderId());
            orderDto.setStatus(PayStatusEnum.PAY_SUCCESS.getCode());
            tOrderService.updateOrder(orderDto);
        }
        return Result.ok();
    }

    private ApplePaySuccessResp getApplePaySuccessResp(String appCode, String userCode) {
        Response<MemberDto> member = memberService.getMemberInfo(userCode, appCode);
        if (member == null) {
            return null;
        }

        ApplePaySuccessResp resp = new ApplePaySuccessResp();
        resp.setMemberType(member.getData().getMemberType());
        resp.setStatus(member.getData().getStatus());
        resp.setExpiryDate(member.getData().getExpiryDate());


        Response<List<MemberBenefitsDto>> list = memberBenefitsService.getMemberBenefits(userCode);
        if (list != null && CollectionUtils.isNotEmpty(list.getData())) {
            List<ApplePaySuccessResp.MemberBenefitsVO> benefits = list.getData().stream().map(item -> {
                ApplePaySuccessResp.MemberBenefitsVO vo = new ApplePaySuccessResp.MemberBenefitsVO();
                vo.setBenefitCode(item.getBenefitCode());
                vo.setMaxUses(item.getMaxUses());
                return vo;
            }).collect(Collectors.toList());

            resp.setBenefits(benefits);
        }

        return resp;
    }

    /**
     * 用户已支付，需要存储支付令牌
     */
    @RequestMapping("/storeToken")
    public Response storeToken(@RequestBody ReceivedPaymentTokenReq receivedPaymentTokenReq) {
        final String userCode = RequestLocalInfo.getCurrentUser().getUserCode();
        String appCode = RequestLocalInfo.getRequestBasicInfo().getAppCode();
        logger.info("[PaymentLog] userCode:{}, orderNo:{}, requestStr:{}", userCode, receivedPaymentTokenReq.getOrderNoTmp(), JSONObject.toJSONString(receivedPaymentTokenReq));

        if (StringUtils.isEmpty(receivedPaymentTokenReq.getPurchase())) {
            logger.error("[PaymentLog] The purchaseToken should not empty, userCode:{}, orderNo:{} params:{}", userCode, receivedPaymentTokenReq.getOrderNoTmp(), JSONObject.toJSONString(receivedPaymentTokenReq));
            return Response.error("The payment token should not empty!");
        }

        final PaymentTokenReq paymentTokenReq = JSONObject.parseObject(receivedPaymentTokenReq.getPurchase(), PaymentTokenReq.class);
        paymentTokenReq.setOrderNoTmp(receivedPaymentTokenReq.getOrderNoTmp());
        logger.info("[PaymentLog] The message from app, userCode:{}, orderNo:{}, messageContent:{}", userCode, receivedPaymentTokenReq.getOrderNoTmp(), JSONObject.toJSONString(receivedPaymentTokenReq));

        // 防止重复推送
        final String token = redisClient.getString(PAY_REQUEST_TOKEN, userCode);
        if (StringUtils.isNotEmpty(token)) {
            logger.error("[PaymentLog] The purchaseToken has exists in records, userCode:{}, orderNo:{}, params:{}", userCode, receivedPaymentTokenReq.getOrderNoTmp(), JSONObject.toJSONString(paymentTokenReq));
            return Response.error("The payment token has exists in records");
        }

        final TOrderDto order = RpcUtils.getResult(tOrderService.queryOrderByOrderNo(paymentTokenReq.getOrderNoTmp()));
        if (Objects.isNull(order)) {
            logger.error("[PaymentLog] The order not exists, orderNo:{}", paymentTokenReq.getOrderNoTmp());
            return Response.error("The order not exists, orderNo:" + paymentTokenReq.getOrderNoTmp());
        } else {
            paymentTokenReq.setAmount(order.getPayableAmount());
        }
        if (Objects.equals(OrderStatus.PAID.getStatus(), order.getStatus())) {
            logger.error("[PaymentLog] The order has paid, orderNo:{}", paymentTokenReq.getOrderNoTmp());
            return Response.error("The order has paid, orderNo:" + paymentTokenReq.getOrderNoTmp());
        }

        // 推送支付数据到adjust
//        asyncPushDataToAppsFlyer(order);

        // 弱网环境下，可能不会传orderId过来， 需要调用api主查查询，获取orderId
        if (StringUtils.isEmpty(paymentTokenReq.getOrderId())) {
            final String productPurchaseStr = RpcUtils.getResult(repayService.queryExtentInfo(buildRepayRequest(paymentTokenReq, userCode, order.getProductCode())));
            if (StringUtils.isNotEmpty(productPurchaseStr)) {
                final JSONObject productPurchaseJson = JSONObject.parseObject(productPurchaseStr);
                paymentTokenReq.setOrderId(productPurchaseJson.getString("orderId"));
                logger.info("[PaymentLog] orderNo:{} orderId:{}", receivedPaymentTokenReq.getOrderNoTmp(), paymentTokenReq.getOrderId());

            }
        }

        // 权益先行发放（支付失败或客户退款同样发放）
        if (generateUserBenefitBeforePaymentCheckFlag) {
            // 普通用户权益先行发放，测试用户需要支付状态确认后再进行权益发放
            if (!apiPaymentUserMock.contains(userCode)) {
                logger.info("[PaymentLog] 普通用户权益先行发放, userCode:{}, orderNo:{} orderId:{}", userCode, receivedPaymentTokenReq.getOrderNoTmp(), paymentTokenReq.getOrderId());
                createUserBenefits(getProductDto(order.getProductCode()), userCode, order.getOrderNo());
            } else {
                logger.info("[PaymentLog] 支付强校验测试用户权益需要支付状态确认后再进行发放, userCode:{}, orderNo:{}, orderId:{}", userCode, receivedPaymentTokenReq.getOrderNoTmp(), paymentTokenReq.getOrderId());
            }
        }

        // 推送到支付系统
        final Response<RepayResponse> repay = pushOrderToPay(paymentTokenReq, userCode, order.getProductCode());
        if (Objects.nonNull(repay) && repay.isSuccess()) {
            logger.info("[PaymentLog] repayService.repay success, userCode:{}, orderNo:{}, orderId:{}", userCode, receivedPaymentTokenReq.getOrderNoTmp(), paymentTokenReq.getOrderId());
        }

        final RepayResponse repayResult = repay.getData();
        if (Objects.isNull(repayResult)) {
            logger.error("[PaymentLog] RepayService.repay failed, userCode:{}, orderId:{}, orderNo:{}, errorMsg:{}", userCode, receivedPaymentTokenReq.getOrderNoTmp(), paymentTokenReq.getOrderId(), repay.getMsg());
        }

        // 更新支付日志数据（此处不影响流程）
        updateForReceiveLog(paymentTokenReq, order);

        // 订单关闭
        if (repayResult.getPayStatusEnum().equals(PayStatusEnum.CLOSED_ORDER)) {
            logger.info("[PaymentLog] order has closed, userCode:{}, orderNo:{}", userCode, order.getOrderNo());
            updateOrderStatus(order, OrderStatus.CLOSE, paymentTokenReq.getOrderId(), paymentTokenReq.getPurchaseToken());
            return Response.ok();
        }

        // 支付成功
        if (repayResult.getPayStatusEnum().equals(PayStatusEnum.PAY_SUCCESS)) {
            logger.info("[PaymentLog] repay success, userCode:{}, orderNo:{}", userCode, order.getOrderNo());
            // 更新订单状态
            updateOrderStatus(order, OrderStatus.PAID, paymentTokenReq.getOrderId(), paymentTokenReq.getPurchaseToken());
            // 权益发放
            if (!generateUserBenefitBeforePaymentCheckFlag) {
                createUserBenefits(getProductDto(order.getProductCode()), userCode, order.getOrderNo());
            } else {
                // 支付强校验测试用户在支付状态确认后再进行权益发放
                if (apiPaymentUserMock.contains(userCode)) {
                    logger.info("[PaymentLog] 支付状态确认后，对测试用户发放权益, userCode:{}, orderNo:{}", userCode, order.getOrderNo());
                    createUserBenefits(getProductDto(order.getProductCode()), userCode, order.getOrderNo());
                }
            }

            try {
                ProductDto productDto = RpcUtils.getResult(productService.queryProductsByProductCode(appCode, order.getProductCode()));
                if (productDto != null && productDto.getProductCategory() != ProductCategory.MEMBER.getCode()) {
                    UserPromotionRecordDto userPromotionRecordDto = userPromotionRecordService.getLastByUserCode(userCode);
                    if (userPromotionRecordDto != null && userPromotionRecordDto.getOperationStatus() == 1) {
                        UserPromotionRecordDto userPromotionRecord = new UserPromotionRecordDto();
                        userPromotionRecord.setId(userPromotionRecordDto.getId());
                        userPromotionRecord.setOperationStatus(2);
                        userPromotionRecordService.UpdateUserPromotionRecord(userPromotionRecord);
                    }
                }
            } catch (Exception e) {
                logger.error("[PaymentLog] UpdateUserPromotionRecord error, userCode:{}, orderNo:{}", userCode, order.getOrderNo());
            }

            return Response.ok();
        }

        if (repayResult.getPayStatusEnum().equals(PayStatusEnum.PROCESSING)) {
            logger.info("[PaymentLog] order is in processing, userCode:{}, orderNo:{}", userCode, order.getOrderNo());

            // 更新订单状态
            updateOrderStatus(order, OrderStatus.PAID, paymentTokenReq.getOrderId(), paymentTokenReq.getPurchaseToken());
            return Response.ok();
        }


        logger.error("StoreToken failed, userCode:{}", userCode);
        return Response.error();
    }


    private void asyncPushDataToAppsFlyer(TOrderDto orderDto) {
        try {
            logger.info("asyncPushDataToAppsFlyerStart:{}", JSONObject.toJSONString(orderDto));
            final HashMap<String, Object> params = Maps.newHashMap();
            params.put("amount", orderDto.getPayableAmount());
            params.put("productCode", orderDto.getProductCode());
            params.put("userCode", orderDto.getUserCode());
            AppsFlyerEventDefType appsFlyerEventDefType = null;
            final Response<Boolean> response = appsflyerService.fetNewAccountFlag(orderDto.getUserCode());
            if (response.isSuccess() && response.getData()) {
                appsFlyerEventDefType = AppsFlyerEventDefType.D0_Purchase;
            }
            // 其它当作非新用户购买处理
            else {
                final RequestBasicInfo requestBasicInfo = RequestLocalInfo.getRequestBasicInfo();
                // meboo应用43号版本之后，不再需要推送购买数据，由前端直接推送
                if (requestBasicInfo.getApplicationID().equals("com.kly.meboo") && Integer.parseInt(requestBasicInfo.getAppVersion()) < 43) {
                    appsFlyerEventDefType = AppsFlyerEventDefType.Purchase;
                }
            }
            if (appsFlyerEventDefType != null) {
                appsflyerService.asyncTraceEvent(appsFlyerEventDefType, params);
            }
        } catch (NumberFormatException e) {
            logger.error("asyncPushDataToAppsFlyerFailed, order:{}", JSONObject.toJSONString(orderDto), e);
        }
    }

    private void asyncPushDataToAdjust(TOrderDto orderDto) {
        try {
            logger.info("asyncPushDataToAdjust:{}", JSONObject.toJSONString(orderDto));
            final HashMap<String, Object> params = Maps.newHashMap();
            params.put("amount", orderDto.getPayableAmount());
            params.put("productCode", orderDto.getProductCode());
            params.put("userCode", orderDto.getUserCode());
            AdjustEventDefType adjustEventDefType = null;
            final Response<Boolean> response = adjustService.fetNewAccountFlag(orderDto.getUserCode());
            if (response.isSuccess() && response.getData()) {
                adjustEventDefType = AdjustEventDefType.D0_Purchase;
            }
            // 其它当作非新用户购买处理
            else {
                adjustEventDefType = AdjustEventDefType.Purchase;
            }
            adjustService.asyncTraceEvent(adjustEventDefType, params);
        } catch (Exception e) {
            logger.error("asyncPushDataToAdjustFailed, order:{}", JSONObject.toJSONString(orderDto), e);
        }
    }

    private void updateForReceiveLog(PaymentTokenReq paymentTokenReq, TOrderDto order) {
        try {
            // 支付回调先于支付凭证存储接口，需要更新一下订支付日志
            final String existsTokenFromNotify = redisClient.getString(ApiRedisKeys.PAY_TOKEN.getValue(), paymentTokenReq.getPurchaseToken());
            if (StringUtils.isNotEmpty(existsTokenFromNotify)) {
                doLog(paymentTokenReq.getPurchaseToken(), order.getOrderNo(), order.getOrderId());
            }
        } catch (Exception e) {
            logger.error("[PaymentLog] UpdateNotifyLogError", e);
        }
    }

    /**
     * 该接口用于项目的支付回调
     */
    @SignIgnore
    @VisitorAccessible
    @RequestMapping("/callback")
    public Response callback(@RequestBody RepayStatusRequest repayStatusRequest) {
        logger.info("====receivedCallback==== params :{}", JSONObject.toJSONString(repayStatusRequest));
        final Response<RepayStatusResponse> response = repayService.repayStatusQuery(repayStatusRequest);

        RepayStatusResponse result = response.getData();
        logger.info("====receivedCallback==== repayStatusQueryResult, orderNo:{}", result.getOrderNo());

        if (!PayStatusEnum.PAY_SUCCESS.equals(result.getStatus())) {
            logger.info("====receivedCallback==== repayStatusFailed, orderNo:{}", result.getOrderNo());
            return Response.error();
        }

        logger.info("[PaymentLog] repay success, userCode:{}, orderNo:{}", repayStatusRequest.getUserCode(), repayStatusRequest.getOrderNo());
        // 更新订单状态
        final TOrderDto order = RpcUtils.getResult(tOrderService.queryOrderByOrderNo(repayStatusRequest.getOrderNo()));
        updateOrderStatus(order, OrderStatus.PAID, order.getOrderId(), order.getPurchaseToken());

        // 权益发放
        createUserBenefits(getProductDto(order.getProductCode()), order.getUserCode(), order.getOrderNo());
        return Response.ok();
    }

    /**
     * 该接口用于google pay的支付消息通知
     */
    @ResponseBody
    @RequestMapping(value = "/receivedGoogleNotify", method = RequestMethod.POST)
    @VisitorAccessible
    @SignIgnore
    public void receivedGoogleNotify(@RequestBody(required = false) byte[] body, HttpServletRequest request, HttpServletResponse response) {

        logger.info("====receivedGoogleNotify==== receivedGoogleNotifyStart:{}", body.length);
        JSONObject paramJson;
        try {
            String paramStr = null;
            String bodyStr;
            try {
                bodyStr = new String(body, "utf-8");
                paramStr = bodyStr;
                //回调具体内容见下方
                logger.info("====receivedGoogleNotify==== receivedGoogleNotifyParams :{}", paramStr);

                doLog(paramStr);
            } catch (Exception e) {
                logger.error("====receivedGoogleNotify==== ParseReceivedGoogleNotifyParamsFailed", e);
                return;
            }
            /**
             * google 推送过来的消息数据格式如下
             * {
             *     "message":{
             *         "data":"eyJ2ZXJzaW9uIjoiMS4wIiwicGFja2FnZU5hbWUiOiJjb20ua2x5Lm1lYm9vIiwiZXZlbnRUaW1lTWlsbGlzIjoiMTY5MDI2NTk3NzU4NyIsInN1YnNjcmlwdGlvbk5vdGlmaWNhdGlvbiI6eyJ2ZXJzaW9uIjoiMS4wIiwibm90aWZpY2F0aW9uVHlwZSI6NCwicHVyY2hhc2VUb2tlbiI6ImJiZ2JucHBsY2dubGZhb21mbG9vb2xvZS5BTy1KMU93ZzFFVWRCWXdaRktwVzBuaFhFclJVZVVTX1o5RnpZQ0RBeGt2ZWZud3VGS1UydFlsUWpTQUJRN2lVMXNxZHBLcXV2UDhQRmR0akdOVS1nd2ZJMDJjQUVFc3JKdyIsInN1YnNjcmlwdGlvbklkIjoibWVib29fc3Vic2NyaXB0aW9uXzEwMSJ9fQ==",
             *         "messageId":"8699697815595258",
             *         "message_id":"8699697815595258",
             *         "publishTime":"2023-07-25T06:19:37.815Z",
             *         "publish_time":"2023-07-25T06:19:37.815Z"
             *     },
             *     "subscription":"projects/meboo-v2/subscriptions/prod-notify-push"
             * }
             */
            if (!StringUtils.isEmpty(paramStr)) {
                paramJson = JSONObject.parseObject(URLDecoder.decode(paramStr, "utf-8"));
                JSONObject msgJson = paramJson.getJSONObject("message");
                String data = msgJson.getString("data");
                String developerNotificationStr = new String(Base64.getDecoder().decode(data), "UTF-8");
                logger.info("====receivedGoogleNotify==== receivedGoogleNotifyParamsData :{}", developerNotificationStr);

                try {
                    /**
                     * developerNotificationJson数据格式如下
                     *  {
                     *      "version":"1.0",
                     *       "packageName":"包名",
                     *       "eventTimeMillis":"时间戳(毫秒)",
                     *       "subscriptionNotification":{
                     *          "version":"1.0",
                     *          "notificationType":4,
                     *          "purchaseToken":"支付令牌",
                     *          "subscriptionId":"订阅的商品id"
                     *      }
                     *  }
                     */
                    JSONObject developerNotificationJson = JSONObject.parseObject(developerNotificationStr);
                    String packageName = developerNotificationJson.getString("packageName");
                    JSONObject oneTimeProductNotificationJson = Optional.ofNullable(developerNotificationJson.getJSONObject("oneTimeProductNotification")).orElse(new JSONObject());
                    JSONObject subscriptionNotificationJson = Optional.ofNullable(developerNotificationJson.getJSONObject("subscriptionNotification")).orElse(new JSONObject());
                    /**
                     * 通知的类型：
                     * (1) SUBSCRIPTION_RECOVERED - 从帐号保留状态恢复了订阅。
                     * (2) SUBSCRIPTION_RENEWED - 续订了处于活动状态的订阅。
                     * (3) SUBSCRIPTION_CANCELED - 自愿或非自愿地取消了订阅。如果是自愿取消，在用户取消时发送。
                     * (4) SUBSCRIPTION_PURCHASED - 购买了新的订阅。
                     * (5) SUBSCRIPTION_ON_HOLD - 订阅已进入帐号保留状态（如已启用）。
                     * (6) SUBSCRIPTION_IN_GRACE_PERIOD - 订阅已进入宽限期（如已启用）。
                     * (7) SUBSCRIPTION_RESTARTED - 用户已通过“Play”>“帐号”>“订阅”重新激活其订阅（需要选择使用订阅恢复功能）。
                     * (8) SUBSCRIPTION_PRICE_CHANGE_CONFIRMED - 用户已成功确认订阅价格变动。
                     * (9) SUBSCRIPTION_DEFERRED - 订阅的续订时间点已延期。
                     * (10) SUBSCRIPTION_PAUSED - 订阅已暂停。
                     * (11) SUBSCRIPTION_PAUSE_SCHEDULE_CHANGED - 订阅暂停计划已更改。
                     * (12) SUBSCRIPTION_REVOKED - 用户在有效时间结束前已撤消订阅。
                     * (13) SUBSCRIPTION_EXPIRED - 订阅已过期。
                     */
                    String purchaseToken = StringUtils.isEmpty(oneTimeProductNotificationJson.getString("purchaseToken")) ? subscriptionNotificationJson.getString("purchaseToken") : oneTimeProductNotificationJson.getString("purchaseToken");
                    // 根据支付令牌查询待处理的订单(可能回调先于storeToken接口调用)

                    final TOrderDto orderDto = RpcUtils.getResult(tOrderService.queryLatestOrderByPurchaseToken(purchaseToken, getAppCodeByPackageName(packageName)));
                    if (Objects.isNull(orderDto)) {
                        logger.error("====receivedGoogleNotify==== TheOrderNotExistsInRecords, receivedNotify:{}", developerNotificationStr);
                        if (StringUtils.isNotEmpty(purchaseToken)) {
                            redisClient.set(ApiRedisKeys.PAY_TOKEN.getValue(), purchaseToken, Constants.EFFECTIVE_IN_10_MINUTE, purchaseToken);
                        }
                        return;
                    }

                    // 日志记录
                    doLog(purchaseToken, orderDto.getOrderNo(), orderDto.getUserCode());

                    // 状态已经确认的订单，不需要处理
                    if (OrderStatus.PAID.getStatus() == orderDto.getStatus() || OrderStatus.CLOSE.getStatus() == orderDto.getStatus()) {
                        // 一次性商品购买
                        if (PurchaseType.ONCE_PRODUCT.getType().equals(orderDto.getPurchaseType())) {
                            logger.error("====receivedGoogleNotify==== TheOrderHasPaidOrClosed, receivedNotify:{}", developerNotificationStr);
                            return;
                        }
                    }

                    // 一次性商品处理
                    if (!oneTimeProductNotificationJson.isEmpty()) {
                        processOneTimeProductsPurchase(oneTimeProductNotificationJson, orderDto);
                        return;
                    }


                    // 订阅类商品处理
                    if (!subscriptionNotificationJson.isEmpty()) {
                        String subscriptionId = subscriptionNotificationJson.getString("subscriptionId");
                        int notificationType = subscriptionNotificationJson.getIntValue("notificationType");
//                        if (notificationType ==2 ) {
//                            subscriptionOrder(packageName, subscriptionNotificationJson, orderDto, purchaseToken, subscriptionId, msgJson);
//                        } else {
                        subscriptionProductsPurchase(packageName, subscriptionNotificationJson, orderDto, msgJson);
//                        }
                        return;
                    }
                    logger.error("====receivedGoogleNotify==== ParseReceivedGoogleNotifyParamsFailed, receivedNotifyParams:{}", developerNotificationStr);
                } catch (Exception e) {
                    logger.error("====receivedGoogleNotify==== ParseReceivedGoogleNotifyParamsFailed, receivedNotifyParams:{}", developerNotificationStr, e);
                }
            }
        } catch (Exception e) {
            logger.error("====receivedGoogleNotify==== ParseReceivedGoogleNotifyParamsFailed", e);
        }
    }

    /**
     * 该接口用于手动添加用户权益
     */
    @ResponseBody
    @RequestMapping(value = "/addUserBenefits", method = RequestMethod.POST)
    @VisitorAccessible
    @SignIgnore
    public void receivedGoogleNotifyTest(@RequestBody AddSubscriptionOrderReq req) {

        try {
            /**
             * developerNotificationJson数据格式如下
             *  {
             *      "version":"1.0",
             *       "packageName":"包名",
             *       "eventTimeM   "notificationType":4,
             *          "purchasillis":"时间戳(毫秒)",
             *              *       "subscriptionNotification":{
             *              *          "version":"1.0",
             *              *       eToken":"支付令牌",
             *          "subscriptionId":"订阅的商品id"
             *      }
             *  }
             */
//            JSONObject developerNotificationJson = JSONObject.parseObject(developerNotificationStr);
            String packageName = req.getPackageName();
            SubscriptionNotificationVO subscriptionNotification = req.getSubscriptionNotification();
            /**
             * 通知的类型：
             * (1) SUBSCRIPTION_RECOVERED - 从帐号保留状态恢复了订阅。
             * (2) SUBSCRIPTION_RENEWED - 续订了处于活动状态的订阅。
             * (3) SUBSCRIPTION_CANCELED - 自愿或非自愿地取消了订阅。如果是自愿取消，在用户取消时发送。
             * (4) SUBSCRIPTION_PURCHASED - 购买了新的订阅。
             * (5) SUBSCRIPTION_ON_HOLD - 订阅已进入帐号保留状态（如已启用）。
             * (6) SUBSCRIPTION_IN_GRACE_PERIOD - 订阅已进入宽限期（如已启用）。
             * (7) SUBSCRIPTION_RESTARTED - 用户已通过“Play”>“帐号”>“订阅”重新激活其订阅（需要选择使用订阅恢复功能）。
             * (8) SUBSCRIPTION_PRICE_CHANGE_CONFIRMED - 用户已成功确认订阅价格变动。
             * (9) SUBSCRIPTION_DEFERRED - 订阅的续订时间点已延期。
             * (10) SUBSCRIPTION_PAUSED - 订阅已暂停。
             * (11) SUBSCRIPTION_PAUSE_SCHEDULE_CHANGED - 订阅暂停计划已更改。
             * (12) SUBSCRIPTION_REVOKED - 用户在有效时间结束前已撤消订阅。
             * (13) SUBSCRIPTION_EXPIRED - 订阅已过期。
             */
            String purchaseToken = subscriptionNotification.getPurchaseToken();
            // 根据支付令牌查询待处理的订单(可能回调先于storeToken接口调用)
            final TOrderDto orderDto = RpcUtils.getResult(tOrderService.queryLatestOrderByPurchaseToken(purchaseToken, getAppCodeByPackageName(packageName)));
            if (Objects.isNull(orderDto)) {
                logger.error("====receivedGoogleNotify==== TheOrderNotExistsInRecords, receivedNotify:{}", JSONObject.toJSONString(req));
                redisClient.set(ApiRedisKeys.PAY_TOKEN.getValue(), purchaseToken, Constants.EFFECTIVE_IN_10_MINUTE, purchaseToken);
                return;
            }

            // 日志记录
            doLog(purchaseToken, orderDto.getOrderNo(), orderDto.getUserCode());

            // 状态已经确认的订单，不需要处理
            if (OrderStatus.PAID.getStatus() == orderDto.getStatus() || OrderStatus.CLOSE.getStatus() == orderDto.getStatus()) {
                // 一次性商品购买
                if (PurchaseType.ONCE_PRODUCT.getType().equals(orderDto.getPurchaseType())) {
                    logger.error("====receivedGoogleNotify==== TheOrderHasPaidOrClosed, receivedNotify:{}", JSONObject.toJSONString(req));
                    return;
                }
            }


            subscriptionProductsPurchase(packageName, JSONObject.parseObject(JSONObject.toJSONString(req.getSubscriptionNotification())), orderDto, null);

        } catch (Exception e) {
            logger.error("====receivedGoogleNotify==== ParseReceivedGoogleNotifyParamsFailed, receivedNotifyParams:{}", JSONObject.toJSONString(req), e);
        }
    }

    /**
     * 订阅通知类型处理：
     * (1) SUBSCRIPTION_RECOVERED - 从帐号保留状态恢复了订阅。
     * (2) SUBSCRIPTION_RENEWED - 续订了处于活动状态的订阅。
     * (3) SUBSCRIPTION_CANCELED - 自愿或非自愿地取消了订阅。如果是自愿取消，在用户取消时发送。
     * (4) SUBSCRIPTION_PURCHASED - 购买了新的订阅。
     * (5) SUBSCRIPTION_ON_HOLD - 订阅已进入帐号保留状态（如已启用）。
     * (6) SUBSCRIPTION_IN_GRACE_PERIOD - 订阅已进入宽限期（如已启用）。
     * (7) SUBSCRIPTION_RESTARTED - 用户已通过“Play”>“帐号”>“订阅”重新激活其订阅（需要选择使用订阅恢复功能）。
     * (8) SUBSCRIPTION_PRICE_CHANGE_CONFIRMED - 用户已成功确认订阅价格变动。
     * (9) SUBSCRIPTION_DEFERRED - 订阅的续订时间点已延期。
     * (10) SUBSCRIPTION_PAUSED - 订阅已暂停。
     * (11) SUBSCRIPTION_PAUSE_SCHEDULE_CHANGED - 订阅暂停计划已更改。
     * (12) SUBSCRIPTION_REVOKED - 用户在有效时间结束前已撤消订阅。
     * (13) SUBSCRIPTION_EXPIRED - 订阅已过期。
     */
    private void subscriptionProductsPurchase(String packageName, JSONObject subscriptionNotificationJson, TOrderDto orderDto, JSONObject msgJson) {
        logger.info("====receivedGoogleNotify==== subscriptionProductsPurchase begin, userCode:{}, orderNo:{}, receivedNotification:{}", orderDto.getUserCode(), orderDto.getOrderNo(), subscriptionNotificationJson.toJSONString());

        String purchaseToken = subscriptionNotificationJson.getString("purchaseToken");
        String subscriptionId = subscriptionNotificationJson.getString("subscriptionId");
        int notificationType = subscriptionNotificationJson.getIntValue("notificationType");

        // SUBSCRIPTION_PURCHASED - 购买了新的订阅
        if (4 == notificationType) {
            RepayStatusResponse repayStatusQueryResult = repayStatusQuery(packageName, subscriptionId, purchaseToken, orderDto.getProductType(), orderDto);

            // 更新订单状态
            if (!PayStatusEnum.PAY_SUCCESS.equals(repayStatusQueryResult.getStatus())) {
                logger.error("====receivedGoogleNotify==== subscriptionProductsPurchaseFailed, userCode:{}, orderNo:{}, receivedNotification:{}", orderDto.getUserCode(), orderDto.getOrderNo(), JSONObject.toJSONString(repayStatusQueryResult));
                return;
            }
            paidSuccess(orderDto, repayStatusQueryResult.getStartTime(), repayStatusQueryResult.getExpiryTime());

            // 进行权益发放
            createUserBenefits(getProductDto(orderDto.getProductCode()), orderDto.getUserCode(), orderDto.getOrderNo());

        }
        /**
         * SUBSCRIPTION_RENEWED - 续订了处于活动状态的订阅
         * 1) 根据现在请求谷歌的googleOrderId获取续订包的订单，获取用户跟productId
         * 2) 续订的谷歌订单是有规则的，比如第一次购买产生的订单是GPA.123-456-789，那第一次续订的产生的订单号是GPA.123-456-789..0，第二次GPA.123-456-789..1，依次类推。
         * 3) 当订阅包降级购买的时候，谷歌并不是通知你购买了新订阅包而是续订，比如你购买的高级订阅包是GPA.123-456-789，当你切换低级的订阅包的时候订单号为GPA.111-222-333..0，你会发现订单号变了，这时候就难办了，拿不到之前用户的信息（谷歌返回的订单参数是没有项目里面用户信息的），经过联调发现，他们两个订单的linkedPurchaseToken是一样的
         * 4) 当降级和自动续订的时候都会走这个通知，所以里面有两个逻辑，需分别判断
         */
        else if (2 == notificationType) {
            subscriptionOrder(packageName, subscriptionNotificationJson, orderDto, purchaseToken, subscriptionId, msgJson);
        }
        // SUBSCRIPTION_CANCELED - 自愿或非自愿地取消了订阅。如果是自愿取消，在用户取消时发送。
        else if (3 == notificationType) {
            logger.info("====receivedGoogleNotify==== canceledSubscriptionSuccess, userCode:{}, orderNo:{}, receivedNotification:{}", orderDto.getUserCode(), orderDto.getOrderNo(), JSONObject.toJSONString(subscriptionNotificationJson));
            memberService.offAutoRenew(orderDto.getUserCode());
            //修改会员信息后，删除会员缓存
            redisClient.del(ApiRedisKeys.USER_MEMBER.getValue(), orderDto.getUserCode());

        }
        // 订阅已进入宽限期（如已启用）。
        else if (6 == notificationType) {
            logger.info("【订阅已进入宽限期】----" + JSONObject.toJSONString(subscriptionNotificationJson));
        }
        // SUBSCRIPTION_RESTARTED - 用户已通过“Play”>“帐号”>“订阅”重新激活其订阅（需要选择使用订阅恢复功能）
        else if (7 == notificationType) {
            logger.info("【重新注册了订阅】----" + JSONObject.toJSONString(subscriptionNotificationJson));
            //用户在谷歌后台重新激活的话，purchaseToken是不变的，我们只需通过Token找出之前的记录更改状态，过期时间是不变的
            paidSuccess(orderDto, null, null);
            // 开关开启时，在生成订单的时候就已经发放了权益，此处只需要修改订单状态
            if (!generateUserBenefitBeforePaymentCheckFlag) {
                createUserBenefits(getProductDto(orderDto.getProductCode()), orderDto.getUserCode(), orderDto.getOrderNo());
            }
        }
        // SUBSCRIPTION_REVOKED - 用户在有效时间结束前已撤消订阅(主要由系统发起）
        else if (12 == notificationType) {
            logger.info("====receivedGoogleNotify==== revokedSubscriptionSuccess, userCode:{}, orderNo:{}, receivedNotification:{}", orderDto.getUserCode(), orderDto.getOrderNo(), JSONObject.toJSONString(subscriptionNotificationJson));
            // TODO: 2023/7/19 调用撤消订阅接口(目前服务后台未开放该功能，不作处理)
        }
        // SUBSCRIPTION_EXPIRED - 订阅已过期
        else if (13 == notificationType) {
            logger.info("====receivedGoogleNotify==== subscriptionExpired, userCode:{}, orderNo:{}, receivedNotification:{}", orderDto.getUserCode(), orderDto.getOrderNo(), JSONObject.toJSONString(subscriptionNotificationJson));
            memberService.offAutoRenew(orderDto.getUserCode());
            //修改会员信息后，删除会员缓存
            redisClient.del(ApiRedisKeys.USER_MEMBER.getValue(), orderDto.getUserCode());
        }

    }

    /**
     * 用于续订失败回调
     */
    @VisitorAccessible
    @SignIgnore
    @RequestMapping("/subscriptionOrder/{messageId}/{data}")
    public String subscriptionOrder(@PathVariable String messageId, @PathVariable String data) {
        if (StringUtils.isEmpty(data)) {
            return StrUtil.EMPTY;
        }

        // 1) 生成订单
        try {
            String developerNotificationStr = new String(Base64.getDecoder().decode(data), "UTF-8");
            JSONObject developerNotificationJson = JSONObject.parseObject(developerNotificationStr);
            JSONObject subscriptionNotificationJson = Optional.ofNullable(developerNotificationJson.getJSONObject("subscriptionNotification")).orElse(new JSONObject());
            String packageName = developerNotificationJson.getString("packageName");
            String purchaseToken = subscriptionNotificationJson.getString("purchaseToken");
            String subscriptionId = subscriptionNotificationJson.getString("subscriptionId");

            final String productPurchaseStr = queryOrderDetailFromGooglePay(packageName, purchaseToken, subscriptionId);
            if (StringUtils.isEmpty(productPurchaseStr)) {
                return "fail: 查询google订单为空";
            }

            JSONObject msgJson = new JSONObject();
            msgJson.put("messageId", messageId);
            String newSubscriptionOrderId = getOrderId(productPurchaseStr, purchaseToken, msgJson);

            // 查询是否存在订单
            final TOrderDto orderDto = RpcUtils.getResult(tOrderService.queryLatestOrderByPurchaseToken(purchaseToken, getAppCodeByPackageName(packageName)));

            final TOrderDto latestSubscriptionOrder = RpcUtils.getResult(tOrderService.queryLatestSubscriptionsOrderByUserCode(orderDto.getUserCode()));
            if (latestSubscriptionOrder != null && latestSubscriptionOrder.getOrderId().equals(newSubscriptionOrderId)) {
                return "ok";
            }
            final TOrderDto subscriptionOrder = RpcUtils.getResult(tOrderService.subscriptionOrder(orderDto.getOrderNo(), newSubscriptionOrderId, purchaseToken));
            // 发放权益
            if (subscriptionOrder != null) {
                final Response addUserBenefitsResult = createUserBenefits(getProductDto(orderDto.getProductCode()), orderDto.getUserCode(), subscriptionOrder.getOrderNo());

                if (addUserBenefitsResult.isSuccess()) {

                    // 更新续订日志状态
                    msgJson.put("orderId", newSubscriptionOrderId);
                    updateSubscriptionLogStatus(msgJson, SubscriptionProcessStatus.PAID, "success");

                    try {
                        // 2）创建支付订单
                        JSONObject payExtJson = new JSONObject();
                        payExtJson.put("packageName", packageName);
                        payExtJson.put("purchaseToken", purchaseToken);
                        payExtJson.put("subscriptionId", subscriptionId);
                        payExtJson.put("productId", subscriptionId);
                        final RepayRequest request = RepayRequest.builder().orderNo(subscriptionOrder.getOrderNo())
                                .productCode(subscriptionId).userCode(subscriptionOrder.getUserCode()).payType(String.valueOf(PayTypeEnum.REPAY.getCode()))
                                .callbackUrl(paymentCallbackUrl).payGateway(PayGatewayEnum.GOOGLE_PAY_SUBSCRIPTIONS.getCode()).payExt(payExtJson.toJSONString()).build();
                        if (Objects.nonNull(subscriptionOrder.getPayableAmount())) {
                            request.setAmount(subscriptionOrder.getPayableAmount().toString());
                        }
                        repayService.repay(request);

                        // 续订成功发送推消息
                        String message = "Subscription payment successfully processed.Go ahead and indulge your desires now ❤\uFE0F\uD83D\uDD25";
                        userMsgService.sendMessage("1113913307465977856", orderDto.getUserCode(), "RC:InfoNtf", message, message);
                    } catch (Exception e) {
                        logger.error("subscriptionOrder, 创建支付订单失败，msgJson:{}", subscriptionNotificationJson.toJSONString(), e);
                    }
                    return "ok";
                }
            }
        } catch (Exception e) {
            logger.error("subscriptionOrderError, messageId:{}, data:{}", messageId, data, e);
        }
        return "fail: 其它";
    }

    public void subscriptionOrder(String packageName, JSONObject subscriptionNotificationJson, TOrderDto orderDto, String purchaseToken, String subscriptionId, JSONObject msgJson) {
        logger.info("====receivedGoogleNotify==== reSubscriptionSuccess, userCode:{}, orderNo:{}, receivedNotification:{}", orderDto.getUserCode(), orderDto.getOrderNo(), JSONObject.toJSONString(subscriptionNotificationJson));

        // 添加续订日志
        addSubscriptionLog(msgJson);

        // 1) 生成订单
        try {
            final String productPurchaseStr = queryOrderDetailFromGooglePay(packageName, purchaseToken, subscriptionId);
            if (StringUtils.isEmpty(productPurchaseStr)) {
                updateSubscriptionLogStatus(msgJson, SubscriptionProcessStatus.PAID_FAILED, "fail: 无可用的google订单, packageName:" + packageName + ", purchaseToken:" + purchaseToken + ",subscriptionId:" + subscriptionId);
                return;
            }
            String newSubscriptionOrderId = getOrderId(productPurchaseStr, purchaseToken, msgJson);

            final TOrderDto latestSubscriptionOrder = RpcUtils.getResult(tOrderService.queryLatestSubscriptionsOrderByUserCode(orderDto.getUserCode()));
            if (latestSubscriptionOrder != null && latestSubscriptionOrder.getOrderId().equals(newSubscriptionOrderId)) {
                updateSubscriptionLogStatus(msgJson, SubscriptionProcessStatus.PAID_FAILED, "fail: 订单已存在, userCode:" + orderDto.getUserCode() + ", orderId:" + newSubscriptionOrderId);
                return;
            }
            final TOrderDto subscriptionOrder = RpcUtils.getResult(tOrderService.subscriptionOrder(orderDto.getOrderNo(), newSubscriptionOrderId, purchaseToken));
            // 发放权益
            if (subscriptionOrder != null) {
                final Response addUserBenefitsResult = createUserBenefits(getProductDto(orderDto.getProductCode()), orderDto.getUserCode(), subscriptionOrder.getOrderNo());

                if (addUserBenefitsResult.isSuccess()) {

                    // 更新续订日志状态
                    msgJson.put("orderId", newSubscriptionOrderId);
                    updateSubscriptionLogStatus(msgJson, SubscriptionProcessStatus.PAID, "success");

                    try {
                        // 2）创建支付订单
                        JSONObject payExtJson = new JSONObject();
                        payExtJson.put("packageName", packageName);
                        payExtJson.put("purchaseToken", purchaseToken);
                        payExtJson.put("subscriptionId", subscriptionId);
                        payExtJson.put("productId", subscriptionId);
                        final RepayRequest request = RepayRequest.builder().orderNo(subscriptionOrder.getOrderNo())
                                .productCode(subscriptionId).userCode(subscriptionOrder.getUserCode()).payType(String.valueOf(PayTypeEnum.REPAY.getCode()))
                                .callbackUrl(paymentCallbackUrl).payGateway(PayGatewayEnum.GOOGLE_PAY_SUBSCRIPTIONS.getCode()).payExt(payExtJson.toJSONString()).build();
                        if (Objects.nonNull(subscriptionOrder.getPayableAmount())) {
                            request.setAmount(subscriptionOrder.getPayableAmount().toString());
                        }
                        repayService.repay(request);

                        // 续订成功发送推消息
                        String message = "Subscription payment successfully processed.Go ahead and indulge your desires now ❤\uFE0F\uD83D\uDD25";
                        userMsgService.sendMessage("1113913307465977856", orderDto.getUserCode(), "RC:InfoNtf", message, message);
                    } catch (Exception e) {
                        logger.error("subscriptionOrder, 创建支付订单失败，msgJson:{}", subscriptionNotificationJson.toJSONString(), e);
                    }

                } else {
                    updateSubscriptionLogStatus(msgJson, SubscriptionProcessStatus.PAID_FAILED, "fail: 权益发放失败");
                }
            } else {
                updateSubscriptionLogStatus(msgJson, SubscriptionProcessStatus.PAID_FAILED, "fail: 订单创建失败");
            }
        } catch (Exception e) {
            logger.error("subscriptionOrderError, params:{}", subscriptionNotificationJson.toJSONString(), e);
            updateSubscriptionLogStatus(msgJson, SubscriptionProcessStatus.PAID_FAILED, e.getMessage());
        }
    }

    private void updateSubscriptionLogStatus(JSONObject msgJson, SubscriptionProcessStatus status, String msg) {
        if (msgJson == null || status == null) {
            return;
        }
        if (SubscriptionProcessStatus.PAID.equals(status)) {
            repayService.subscriptionSuccess(msgJson.getString("orderId"), msg);
        } else {
            repayService.updateSubscriptionStatus(msgJson.getString("messageId"), status, msg);

        }
    }

    private void addSubscriptionLog(JSONObject msgJson) {
        try {
            if (msgJson == null) {
                return;
            }
            final ReceiveNotifyRequest receiveNotifyRequest = ReceiveNotifyRequest.builder().receiveNotifyMsg(msgJson.toJSONString()).messageId(msgJson.getString("messageId")).build();
            repayService.addSubscriptionLog(receiveNotifyRequest);
        } catch (Exception e) {
            logger.error("addSubscriptionLogError, msgJson:{}", msgJson.toJSONString());
        }
    }

    /**
     * 调用google api 获取订单信息
     */
    private String queryOrderDetailFromGooglePay(String packageName, String purchaseToken, String subscriptionId) {
        JSONObject extJson = new JSONObject();
        extJson.put("packageName", packageName);
        extJson.put("subscriptionId", subscriptionId);
        extJson.put("purchaseToken", purchaseToken);
        final RepayRequest repayRequest = RepayRequest.builder().payExt(extJson.toJSONString()).payGateway(PayGatewayEnum.GOOGLE_PAY_SUBSCRIPTIONS.getCode()).build();
        return RpcUtils.getResult(repayService.queryExtentInfo(repayRequest));
    }

    /**
     * 获取google订单号
     */
    private String getOrderId(String productPurchaseStr, String purchaseToken, JSONObject msgJson) {
        String orderId = null;
        if (StringUtils.isNotEmpty(productPurchaseStr)) {
            final JSONObject productPurchaseJson = JSONObject.parseObject(productPurchaseStr);
            if ("ACKNOWLEDGEMENT_STATE_ACKNOWLEDGED".equals(productPurchaseJson.getString("acknowledgementState"))) {
                orderId = productPurchaseJson.getString("orderId");
                if (StringUtils.isEmpty(orderId)) {
                    orderId = productPurchaseJson.getString("latestOrderId");
                }
            }
        }

        // 更新日志表中的orderId与token
        if (msgJson!= null && msgJson.containsKey("messageId")) {
            repayService.updateSubscription(msgJson.getString("messageId"), purchaseToken, orderId);
        }
        return orderId;
    }

    /**
     * 一次性商品处理逻辑
     * @param oneTimeProductNotificationJson
     * @param orderDto
     */
    private void processOneTimeProductsPurchase(JSONObject oneTimeProductNotificationJson, TOrderDto orderDto ) {
        logger.info("====receivedGoogleNotify==== processOneTimeProductsPurchase, userCode:{}, orderNo:{}, oneTimeProductNotificationJson:{}", orderDto.getUserCode(), orderDto.getOrderNo(), oneTimeProductNotificationJson.toJSONString());
        if (!oneTimeProductNotificationJson.isEmpty()) {
            /**
             * 通知的类型。它可以具有以下值：
             * (1) ONE_TIME_PRODUCT_PURCHASED - 用户成功购买了一次性商品。
             * (2) ONE_TIME_PRODUCT_CANCELED - 用户已取消待处理的一次性商品购买交易。
             */
            int oneTimeNotificationType = oneTimeProductNotificationJson.getIntValue("notificationType");
            // 用户成功购买了一次性商品
            if (oneTimeNotificationType == 1) {
                final RepayStatusRequest request = RepayStatusRequest.builder().orderNo(orderDto.getOrderNo()).userCode(orderDto.getUserCode()).payGateway(PayGatewayEnum.GOOGLE_PAY.getCode()).build();
                final RepayStatusResponse result = RpcUtils.getResult(repayService.repayStatusQuery(request));
                logger.info("====receivedGoogleNotify==== repayServiceRepayStatusQueryResult, userCode:{}, orderNo:{}, result:{}", orderDto.getUserCode(), orderDto.getOrderNo(), JSONObject.toJSONString(result));
                if (Objects.nonNull(result)) {
                    if (PayStatusEnum.PAY_SUCCESS.equals(result.getStatus())) {
                        updateOrderStatus(orderDto, OrderStatus.PAID, null, null);
                    }
                }
            }
            // 用户已取消待处理的一次性商品购买交易
            else if (oneTimeNotificationType == 2) {
                // TODO: 2023/7/17 用户取消购买一次商品
            }
        }
    }

    /**
     * 接收报文日志记录
     */
    private void doLog(String paramStr) {
        try {
            if (StringUtils.isNotEmpty(paramStr)) {
                JSONObject paramJson = JSONObject.parseObject(URLDecoder.decode(paramStr, "utf-8"));
                JSONObject msgJson = paramJson.getJSONObject("message");
                String data = msgJson.getString("data");
                String developerNotificationStr = new String(Base64.getDecoder().decode(data), "UTF-8");
                JSONObject developerNotificationJson = JSONObject.parseObject(developerNotificationStr);
                JSONObject oneTimeProductNotificationJson = Optional.ofNullable(developerNotificationJson.getJSONObject("oneTimeProductNotification")).orElse(new JSONObject());
                JSONObject subscriptionNotificationJson = Optional.ofNullable(developerNotificationJson.getJSONObject("subscriptionNotification")).orElse(new JSONObject());
                String purchaseToken = StringUtils.isEmpty(oneTimeProductNotificationJson.getString("purchaseToken")) ? subscriptionNotificationJson.getString("purchaseToken") : oneTimeProductNotificationJson.getString("purchaseToken");
                final ReceiveNotifyRequest receiveNotifyRequest = ReceiveNotifyRequest.builder().token(purchaseToken).messageId(paramJson.getString("messageId")).receiveTime(paramJson.getString("publishTime")).receiveNotifyMsg(paramJson.toJSONString()).build();
                repayService.receiveNotify(receiveNotifyRequest);
            }
        } catch (Exception e) {
            logger.error("ReceiveNotifyLogError, paramStr:{}", paramStr, e);
        }
    }

    /**
     * 接收报文日志记录
     */
    private void doLog(String purchaseToken, String orderNo, String orderId) {
        try {
            final ReceiveNotifyRequest receiveNotifyRequest = ReceiveNotifyRequest.builder()
                    .token(purchaseToken).orderId(orderId).orderNo(orderNo).build();
            repayService.storeOrderInfo(receiveNotifyRequest);
        } catch (Exception e) {
            logger.error("UpdateNotifyLogError, purchaseToken:{}", purchaseToken, e);
        }
    }

    public static void main(String[] args) throws UnsupportedEncodingException {
        String data = "eyJ2ZXJzaW9uIjoiMS4wIiwicGFja2FnZU5hbWUiOiJjb20ua2x5Lm1lYm9vIiwiZXZlbnRUaW1lTWlsbGlzIjoiMTY4OTkxODA4MjY3NyIsInN1YnNjcmlwdGlvbk5vdGlmaWNhdGlvbiI6eyJ2ZXJzaW9uIjoiMS4wIiwibm90aWZpY2F0aW9uVHlwZSI6MiwicHVyY2hhc2VUb2tlbiI6ImVvaWdmbWhsaGNvZm5wZ2dnbGJqYWRwYS5BTy1KMU94R1otVm5GU2dLUmI0Z1BjUXdQM0pLbDNkem1fM0pIVUpiSzFFeDk0ZTRibGMzcWg0YkpwcnBXRWE4RFRlWVBtNWx4eGFwZnFENjdBWnVNQ1lEcGJ5c2tNVGZEdyIsInN1YnNjcmlwdGlvbklkIjoibWVib29fc3Vic2NyaXB0aW9uXzEwMSJ9fQ==";
        String developerNotificationStr = new String(Base64.getDecoder().decode(data), "UTF-8");
        System.out.println(developerNotificationStr);
    }

    /**
     * 调用google api获取购买信自，该方法同时更新支付状态
     * @return
     */
    public RepayStatusResponse repayStatusQuery(String packageName, String subscriptionId, String purchaseToken, Integer purchaseType, TOrderDto orderDto) {
        JSONObject req = new JSONObject();
        req.put("packageName", packageName);
        req.put("purchaseToken", purchaseToken);
        req.put("subscriptionId", subscriptionId);
        req.put("productId", subscriptionId);
        req.put("purchaseType", purchaseType);
        req.put("orderId", orderDto.getOrderId());

        final RepayStatusRequest request = RepayStatusRequest.builder().orderNo(orderDto.getOrderNo()).userCode(orderDto.getUserCode()).purchaseToken(purchaseToken).payGateway(PayGatewayEnum.GOOGLE_PAY_SUBSCRIPTIONS.getCode()).build();
        final RepayStatusResponse result = RpcUtils.getResult(repayService.repayStatusQuery(request));

        if (Objects.isNull(result)) {
            logger.error("The account has no subscriptions, packageName:{}, purchaseToken:{}", packageName, purchaseToken);
            return null;
        }

        return result;

    }


    private Response<RepayResponse> pushOrderToPay(PaymentTokenReq paymentTokenReq, String userCode, String productCode) {
        final long startTime = System.currentTimeMillis();
        final RepayRequest repayRequest = buildRepayRequest(paymentTokenReq, userCode, productCode);
        final Response<RepayResponse> repay = repayService.repay(repayRequest);
        logger.info("[PaymentLog] repayService.repay success, userCode:{}, request:{}, result:{}, costTime:{}", userCode, JSONObject.toJSONString(paymentTokenReq), JSONObject.toJSONString(repay), (System.currentTimeMillis() - startTime));
        return repay;
    }

    private RepayRequest buildRepayRequest(PaymentTokenReq paymentTokenReq, String userCode, String productCode) {

        ProductDto productDto = getProductDto(productCode);
        final Integer purchaseType = productDto.getPurchaseType();

        final RepayRequest repayRequest = RepayRequest.builder().orderNo(paymentTokenReq.getOrderNoTmp())
                .productCode(paymentTokenReq.getProductId()).userCode(userCode).payType(String.valueOf(PayTypeEnum.REPAY.getCode()))
                .callbackUrl(paymentCallbackUrl).payExt(JSONObject.toJSONString(paymentTokenReq)).build();

        if (Objects.nonNull(paymentTokenReq.getAmount())) {
            repayRequest.setAmount(paymentTokenReq.getAmount().toString());
        }
        if (purchaseType.equals(purchaseProductType)) {
            repayRequest.setPayGateway(PayGatewayEnum.GOOGLE_PAY.getCode());
        } else if (purchaseType.equals(purchaseProductTypeSubscriptions)) {
            repayRequest.setPayGateway(PayGatewayEnum.GOOGLE_PAY_SUBSCRIPTIONS.getCode());
        }
        return repayRequest;
    }


    private void updateOrderStatus(TOrderDto order, OrderStatus orderStatus, String orderId, String purchaseToken) {
        TOrderDto tOrderDto = new TOrderDto();
        tOrderDto.setOrderNo(order.getOrderNo());
        tOrderDto.setOrderId(orderId);
        tOrderDto.setStatus(orderStatus.getStatus());
        tOrderDto.setPurchaseToken(purchaseToken);
        RpcUtils.getResult(tOrderService.updateOrder(tOrderDto));
    }

    private void paidSuccess(TOrderDto order, String startTime, String expiryTime) {
        TOrderDto tOrderDto = new TOrderDto();
        tOrderDto.setOrderNo(order.getOrderNo());
        tOrderDto.setStatus(OrderStatus.PAID.getStatus());
        tOrderDto.setStartTime(startTime);
        tOrderDto.setExpiryTime(expiryTime);
        tOrderDto.setBenefitsStatus(BenefitsStatus.ISSUED.getStatus());
        RpcUtils.getResult(tOrderService.updateOrder(tOrderDto));
    }

    /**
     * 查询订单信息
     */
    @RequestMapping("/queryOrder")
    public Response queryOrder() {
        String userCode = getCurrentUserCode();
        return tOrderService.queryOrder(userCode);
    }

    private Response<TOrderDto> createUserBenefits(ProductDto productDto, String userCode, String orderNo) {
        ProductCategory category = ProductCategory.fromType(productDto.getProductCategory());
        final TOrderDto order = RpcUtils.getResult(tOrderService.queryOrderByOrderNo2(orderNo));
        if (BenefitsStatus.ISSUED.getStatus() == order.getBenefitsStatus()) {
            logger.info("TheBenefitsHasGrantedForAccount, orderNo:{}", orderNo);
            return Response.ok();
        }
        switch (category) {
            case MEMBER:
            case USER_BACK_DISCOUNT:
            case USER_DISCOUNT:
            case SURPRISE_EASTER_EGG:
            case IOS_MEBOO:
                //模拟订单完成调用赋予会员权益接口
                Response<MemberDto> memberInfo = memberService.saveOrUpdateMember(userCode, productDto);
                memberBenefitsService.saveMemberBenefits(memberInfo.getData(), productDto);
                break;
            case FLASH_CHAT:
            case PRIVATE_PHOTO:
            case PRIVATE_VIDEO:
                userVasPurchasesService.saveUserPurchasesBenefits(userCode, productDto);
                break;
        }
        try {
            if (category == MEMBER || category == USER_BACK_DISCOUNT || category == USER_DISCOUNT || category == SURPRISE_EASTER_EGG || category == IOS_MEBOO) {
                //发送通知消息
                logger.info("====receivedGoogleNotify==== notice begin, userCode:{}", userCode);
                String message = "\uD83D\uDC51 Congratulations on unlocking Premium privileges. Start using them now! \uD83D\uDE08 Go for it and choose from 10,000+ sweet girls!";
                userMsgService.sendMessage(AppCodeEnum.MEBOO.getAppCode(), userCode, "RC:InfoNtf", message, message);
                logger.info("====receivedGoogleNotify==== notice end, userCode:{}", userCode);
            }
        } catch (Exception e) {
            logger.error("====receivedGoogleNotify==== notice, message:{}", e.getMessage());
        }

        // 更新发放标志
        logger.info("===权益发放, order={}", JSONObject.toJSONString(order));
        order.setBenefitsStatus(BenefitsStatus.ISSUED.getStatus());
        tOrderService.updateOrder(order);
        return Response.ok(order);
    }

    private TOrderDto addOrder(@RequestBody @Valid CreateOrderReq createOrderReq, ProductDto productDto, String userCode) {
        AddOrderReq addOrderReq = new AddOrderReq();
        addOrderReq.setProductDto(productDto);
        addOrderReq.setUserCode(userCode);
        addOrderReq.setModelUserCode(createOrderReq.getModelUserCode());
        addOrderReq.setAppVersionName(RequestLocalInfo.getRequestBasicInfo().getAppVersionName());

        return RpcUtils.getResult(tOrderService.saveOrder(addOrderReq));
    }
}
